<?php

namespace app\api\model;

use app\common\model\User as UserModel;
//use app\api\model\Wxapp;
use app\common\library\wechat\WxUser;
use app\common\exception\BaseException;
use think\facade\Cache;
use think\Request;
use service\DataService;
use think\Db;
use app\common\model\Enum;

/**
 * 用户模型类
 * Class User
 * @package app\api\model
 */
class User extends UserModel
{
    private $token;

    public function getUserId($id)
    {
        return Db::table('user')->where("id",$id)->find();
    }

    public function getUserApsid($apsid)
    {
        return Db::table('user')->where("apsid",$apsid)->find();
    }

    public function getUserOpenid($openid)
    {
        return Db::table('user')->where("openid",$openid)->find();
    }


    /**
     * 隐藏字段
     * @var array
     */
    protected $hidden = [
        'wxapp_id',
        'create_time',
        'update_time'
    ];

    /**
     * 获取用户信息
     * @param $token
     * @return null|static
     * @throws \think\exception\DbException
     */
    public static function getUser($token)
    {
        return self::detail(['open_id' => Cache::get($token)['openid']]);
    }

    /**
     * 用户登录
     * @param array $post
     * @return string
     * @throws BaseException
     * @throws \think\Exception
     * @throws \think\exception\DbException //user_
     */
    public function login($post)
    {
        // 微信登录 获取session_key
        $session = $this->wxlogin($post['code']);
        // 自动注册用户
        $userInfo = json_decode(htmlspecialchars_decode($post['info']), true);
        
        $ba=[];
        $this->decryptData(Enum::wxconfig['app_id'],$session['session_key'],$post['encrypted_data'],$post['iv'],$ba);
        //var_dump($ba);
        // var_dump($session['session_key']);
        if(empty($ba)){
            return null;
        }
        $unionId= $ba->unionId;
        if(empty($unionId)){
            return null;
        }

      //var_dump( $unionId);
        $userInfo = $this->register($session['openid'], $userInfo, $unionId);
        
        //decryptData($appid,$sessionKey,$encryptedData, $iv, &$data )

        // 生成token (session3rd)
        $this->token = $this->token($session['openid']);
        // 记录缓存, 7天
        Cache::set($this->token, $session, 86400 * 7);
        return $userInfo;
    }

	public function login_old($post)
    {
        // 微信登录 获取session_key
        $session = $this->wxlogin($post['code']);
        // 自动注册用户
        $userInfo = json_decode(htmlspecialchars_decode($post['info']), true);
        
        $ba=[];
        $this->decryptData(Enum::wxconfig['app_id'],$session['session_key'],$post['encrypted_data'],$post['iv'],$ba);
        $unionId= $ba->unionId;
        $userInfo = $this->register_old($post['apsid'], $userInfo, $unionId);
        return $unionId;
    }


    /**
     * 获取token
     * @return mixed
     */
    public function getToken()
    {
        return $this->token;
    }

    /**
     * 微信登录
     * @param $code
     * @return array|mixed
     * @throws BaseException
     * @throws \think\exception\DbException
     */
    private function wxlogin($code)
    {
		// appid=wxb4f3c62fa7640607
// secret=337f141c6f89d1cf622e2dc7f017b207

        // 微信登录 (获取session_key)
        $WxUser = new WxUser(Enum::wxconfig['app_id'], Enum::wxconfig['app_secret']);
		$session = $WxUser->sessionKey($code);
        if (!$session) {
            throw new BaseException(['msg' => $WxUser->getError()]);
        }
        return $session;
    }

    /**
     * 生成用户认证的token
     * @param $openid
     * @return string
     */
    private function token($openid)
    {
        $wxapp_id = self::$wxapp_id;
        // 生成一个不会重复的随机字符串
        $guid = \getGuidV4();
        // 当前时间戳 (精确到毫秒)
        $timeStamp = microtime(true);
        // 自定义一个盐
        $salt = 'token_salt';
        return md5("{$wxapp_id}_{$timeStamp}_{$openid}_{$guid}_{$salt}");
    }

    /**
     * 自动注册用户
     * @param $open_id
     * @param $userInfo
     * @return mixed
     * @throws BaseException
     * @throws \think\exception\DbException
     */
    private function register($open_id, $userInfo, $unionId)
    {
		//{"nickName":"网站建设","gender":0,"language":"zh_CN","city":"","province":"","country":"","avatarUrl":"https://wx.qlogo.cn/mmopen/vi_32/dibMDqnB5UCmwvMmHppChfnOvCGz2Jnd9tjbunIFAGeekQ2icYK3udbekD8Y86BhJfFO6ak5yo7ZaobY0HkEEPtg/132"}

        $user =Db::table('user')->where("union_id",$unionId)->find();
        if (!empty($user)) {
            // $apsid = md5($open_id);
            //判断aspid 是否存在 , 这里主要是考虑旧用户
            // $user =Db::table('user')->where("apsid",$apsid)->find();
        }

        $userInfo['open_id'] = $open_id;
        $userInfo['union_id'] = $unionId;

		if (empty($user)) {
            $userInfo['wxapp_id'] = self::$wxapp_id;
			$userInfo['create_at'] = date('Y-m-d H:i:s',time());
            $userInfo['apsid'] = md5($open_id);
            $userInfo['code'] =  self::GetCardMax();
        }
        else{
            $userInfo['code'] = $user["code"];
            $userInfo['id'] = $user["id"];
		}

		$userInfo['user_name'] = preg_replace('/[\xf0-\xf7].{3}/', '', $userInfo['nickName']);
		$userInfo['update_at'] = date('Y-m-d H:i:s',time());
		
		if (empty($user)) {
			$id=Db::table('user')->strict(false)->insertGetId($userInfo);
			$userInfo['id'] =$id;
		}
		else{
			Db::table('user')->where('id',$user['id'])->update(['user_name' => $userInfo['user_name'],'update_at'=>$userInfo['update_at'],'open_id'=>$userInfo['open_id'],'union_id'=>$userInfo['union_id']]);
		}
		
        return $userInfo;
    }
	
	private function register_old($apsid, $userInfo, $unionId)
    {
		//{"nickName":"网站建设","gender":0,"language":"zh_CN","city":"","province":"","country":"","avatarUrl":"https://wx.qlogo.cn/mmopen/vi_32/dibMDqnB5UCmwvMmHppChfnOvCGz2Jnd9tjbunIFAGeekQ2icYK3udbekD8Y86BhJfFO6ak5yo7ZaobY0HkEEPtg/132"}
        
        Db::table('user')->where('apsid',$apsid)->update(['union_id' => $unionId, 'update_at' => date('Y-m-d H:i:s',time()) ]);
        
        //这里很重要,就要去新的系统去同步你的账号信息
        Db::connect('db_new')->table('user')->where('apsid',$apsid)->update(['union_id' => $unionId, 'update_at' => date('Y-m-d H:i:s',time()) ]);
        
        return $userInfo;
    }

    private function GetCardMax(){
        $number_max =Db::table('number_max')->where("id",1)->find();
        if(empty($number_max)){
            $maxcard = 11000;//初始
            $data=array(
                'maxnum'=> $maxcard
            );
            Db::table('number_max')->strict(false)->insertGetId($data);
        }else{
            $maxcard = $number_max['maxnum'];
        }
    
        $strMaxcardid = $maxcard + 1;
        // $ar = str_split($strMaxcardid);
        // foreach($ar as $k => $v) {
        //     if ($v == 4 ) {
        //         $ar[$k] ++;
        //         break;
        //     }
        // }
        // $strMaxcardid = join('', $ar);
        $maxcard = $strMaxcardid;
        Db::table('number_max')->where('id',1)->update(['maxnum' => $maxcard]);
        return  $maxcard;
    }
    
    

    private $appid;
	private $sessionKey;
    private $blockSize = 16;

	private $OKs = 0;
	private $IllegalAesKey = -41001;
	private $IllegalIv = -41002;
	private $IllegalBuffer = -41003;
	private $DecodeBase64Error = -41004;

    /**
	 * 检验数据的真实性，并且获取解密后的明文.
	 * @param $encryptedData string 加密的用户数据
	 * @param $iv string 与用户数据一同返回的初始向量
	 * @param $data string 解密后的原文
     *
	 * @return int 成功0，失败返回对应的错误码
	 */
	public function decryptData($appid,$sessionKey,$encryptedData, $iv, &$data )
	{
		$this->sessionKey = $sessionKey;
		$this->appid = $appid;

		if (strlen($this->sessionKey) != 24) {
			return $this->IllegalAesKey;
		}
		$aesKey=base64_decode($this->sessionKey);
		if (strlen($iv) != 24) {
			return $this->IllegalIv;
		}
        $aesIV=base64_decode($iv);
		$aesCipher=base64_decode($encryptedData);
		$result = $this->decrypt($aesKey,$aesCipher,$aesIV);
		if ($result[0] != 0) {
			return $result[0];
		}

        $dataObj=json_decode($result[1]);

        if( $dataObj  == NULL )
        {
			return $this->IllegalBuffer;
        }
        if( $dataObj->watermark->appid != $this->appid )
        {
			return $this->IllegalBuffer;
        }
		$data = $dataObj; //$result[1];
		return $this->OKs;
	}

	/**
	 * 对密文进行解密
	 * @param string $aesCipher 需要解密的密文
	 * @param string $aesIV 解密的初始向量
	 * @return string 解密得到的明文
	 */
	private function decrypt($key, $aesCipher, $aesIV )
	{
		try {

			// $module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');

			// mcrypt_generic_init($module, $key, $aesIV);

			// //解密
			// $decrypted = mdecrypt_generic($module, $aesCipher);
			// mcrypt_generic_deinit($module);
            // mcrypt_module_close($module);
            
            $decrypted = openssl_decrypt($aesCipher, 'AES-128-CBC', $key, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $aesIV);

		} catch (Exception $e) {
			return array($this->IllegalBuffer, null);
		}


		try {
			//去除补位字符
			$result = $this->decode($decrypted);

		} catch (Exception $e) {
			//print $e;
			return array($this->IllegalBuffer, null);
		}
		return array(0, $result);
	}

	/**
	 * 对需要加密的明文进行填充补位
	 * @param $text 需要进行填充补位操作的明文
	 * @return 补齐明文字符串
	 */
	private function encode($text)
	{
		$block_size = $this->blockSize;
		$text_length = strlen( $text );
		//计算需要填充的位数
		$amount_to_pad = $this->blockSize - ( $text_length % $this->blockSize );
		if ( $amount_to_pad == 0 ) {
			$amount_to_pad = $this->blockSize;
		}
		//获得补位所用的字符
		$pad_chr = chr( $amount_to_pad );
		$tmp = "";
		for ( $index = 0; $index < $amount_to_pad; $index++ ) {
			$tmp .= $pad_chr;
		}
		return $text . $tmp;
	}

	/**
	 * 对解密后的明文进行补位删除
	 * @param decrypted 解密后的明文
	 * @return 删除填充补位后的明文
	 */
	private function decode($text)
	{
		$pad = ord(substr($text, -1));
		if ($pad < 1 || $pad > 32) {
			$pad = 0;
		}
		return substr($text, 0, (strlen($text) - $pad));
	}







}
